﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;
using Autofac.Core;
using Cloak.Globalization;

namespace Cloak.Mvp.Autofac.ViewParameters
{
	/// <summary>
	/// Extension methods for resolving view parameters during resolution of presenter instances
	/// </summary>
	public static class ViewParameterResolutionExtensions
	{
		/// <summary>
		/// Casts the value of the <see cref="ViewParameter"/> instance to the specified type
		/// </summary>
		/// <typeparam name="T">The type to which the view is cast</typeparam>
		/// <param name="parameters">The parameters containing the <see cref="ViewParameter"/> instance</param>
		/// <returns>The value of the <see cref="ViewParameter"/> instance, cast to <typeparamref name="T"/></returns>
		/// Thrown if <paramref name="parameters"/> does not contain exactly one instance of <see cref="ViewParameter"/>
		/// </exception>
		/// <exception cref="InvalidCastException">
		/// Thrown if the value of the <see cref="ViewParameter"/> instance cannot be cast to <typeparamref name="T"/>
		/// </exception>
		public static T View<T>(this IEnumerable<Parameter> parameters) where T : class
		{
			Contract.Requires(parameters != null);

			var viewParameters = parameters.OfType<ViewParameter>().ToList();

			if(viewParameters.Count == 0)
			{
				throw new ArgumentException(Resources.NoViewParameter.FormatInvariant(typeof(ViewParameter)), "parameters");
			}

			if(viewParameters.Count > 1)
			{
				throw new ArgumentException(Resources.MultipleViewParameters.FormatInvariant(typeof(ViewParameter)), "parameters");
			}

			var viewParameter = viewParameters.Single();

			var view = viewParameter.Value as T;

			if(view == null)
			{
				if(viewParameter.Value == null)
				{
					throw new InvalidCastException(Resources.ViewParameterNull.FormatInvariant(typeof(ViewParameter)));
				}
				else
				{
					throw new InvalidCastException(Resources.UnableToCastView.FormatInvariant(
						viewParameter.Value.GetType(),
						typeof(T)));
				}
			}

			return view;
		}
	}
}